package com.im.common.netty.chat.handler;

import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import java.util.HashSet;
import java.util.Set;

/**
 * `ChannelInboundHandlerAdapter` 是 Netty 中用于处理入站事件的适配器类，它实现了 `ChannelInboundHandler` 接口，可以方便地处理各种入站事件。具体来说，`ChannelInboundHandlerAdapter` 可以处理的入站事件包括：
 * <p>
 * - `channelRegistered(ChannelHandlerContext ctx)`：当连接已经被建立时调用。
 * - `channelActive(ChannelHandlerContext ctx)`：当连接已经被建立并且可以进行通信时调用。
 * - `channelRead(ChannelHandlerContext ctx, Object msg)`：当从客户端接收到数据时调用。
 * - `channelReadComplete(ChannelHandlerContext ctx)`：当读取完从客户端接收到的数据后调用。
 * - `channelInactive(ChannelHandlerContext ctx)`：当连接已经被关闭时调用。
 * - `exceptionCaught(ChannelHandlerContext ctx, Throwable cause)`：当处理过程中在 ChannelPipeline 中有异常抛出时调用。
 * <p>
 * 通过继承 `ChannelInboundHandlerAdapter` 类并重写上述方法，我们可以编写自定义的处理器，用于实现特定的业务逻辑。
 * 在下面的代码中，我们编写了一个自定义的处理器 `DiscardServerHandler`，用于处理客户端发送的字符串，并将其原样返回给客户端。
 */
public class DiscardServerHandler extends ChannelInboundHandlerAdapter {

    static Set<Channel> channelList = new HashSet<>();

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        // 通知其他人 我上线了
        channelList.forEach(e -> {
            e.writeAndFlush("[客户端]" + ctx.channel().remoteAddress() + "上线了");
        });
        channelList.add(ctx.channel());
    }

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        String message = (String) msg;
        System.out.println("收到数据：" + message);
        // 分发给聊天室内的所有客户端
        // 通知其他人 我上线了
        channelList.forEach(e -> {
            if (e == ctx.channel()) {
                e.writeAndFlush("[自己] ： " + message);
            } else {
                e.writeAndFlush("[客户端] " + ctx.channel().remoteAddress() + "：" + message);
            }
        });
    }

    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        // 通知其他客户端 我下线了
        channelList.remove(ctx.channel());
        // 通知其他人 我上线了
        channelList.forEach(e -> {
            e.writeAndFlush("[客户端]" + ctx.channel().remoteAddress() + "下线了");
        });
    }
}
